#ifndef _MONGCPP_H__
#define _MONGCPP_H__

#include <string>
#include <map>
#include <vector>


#include "mongoose.h"

namespace mongoose
{

	// ----------------------------------------------------------------------------
	// Simple type definitions
	// ----------------------------------------------------------------------------
	enum MongooseRequestMethodCode 
	{
		rmcUndef,
		rmcGet,
		rmcPost,
		rmcHead,
		rmcPut,
		rmcDelete,
		rmcTrace,
		rmcOptions
	};

	typedef std::map<std::string, std::string> ServerOptionSet;
	typedef std::vector<std::string> ServerOptionList;
	typedef std::vector<const char *> ServerOptionStorage;
	typedef std::map<std::string, std::string> RequestValueSet;
	typedef std::map<std::string, int> ResponseValueIndex;
	typedef std::vector<std::pair<std::string, std::string> > ResponseValueList;
	typedef enum mg_event ServerHandlingEvent;
	typedef std::map<std::string, MongooseRequestMethodCode> MethodMap;

	class MongooseConnection {
	public:
		MongooseConnection(struct mg_connection *conn);
		virtual ~MongooseConnection();
		int write(const void *buf, size_t len);
		int write(const std::string &text);
		int read(void *buf, size_t len);
		void sendAuthorizationRequest(const std::string &nonce = "");
		bool getHeader(const std::string &name, std::string &output) const;
		bool getCookie(const std::string &name, std::string &output) const;
	protected:
		struct mg_connection *getInfo();
	protected:
		struct mg_connection *m_conn;
	};

	class MongooseRequest {
	public:
		MongooseRequest(struct mg_connection *conn, mg_request_info* info);
		virtual ~MongooseRequest();
		const std::string getRequestMethod() const;
		MongooseRequestMethodCode getRequestMethodCode() const;
		const std::string getUri() const;
		const std::string getHttpVersion() const;
		const std::string getQueryString() const;
		const std::string readQueryString() const;
		const std::string getRemoteUser() const;
		const std::string getLogMessage() const;
		long getRemoteIp() const;
		int getRemotePort() const;
		int getStatusCode() const;
		bool isSsl() const;
		bool getVar(const std::string &name, std::string &output) const;
	protected:
		mg_request_info* getInfo() const;
	protected:
		mg_request_info* m_info;
		struct mg_connection *m_conn;
	};

	class MongooseResponse {
	public:
		MongooseResponse(struct mg_connection *conn);
		virtual ~MongooseResponse();
		virtual void write();
		void setStatus(int code, const std::string &statusDesc = "", const std::string &httpVer = "");
		void setSetCookie(const std::string &name, const std::string &value);
		void setLocation(const std::string &value = "");
		void setContentType(const std::string &value = "");
		bool getHeaderValue(const std::string &name, std::string &output);
		void addHeaderValue(const std::string &name, const std::string &value);
		void setHeaderValue(const std::string &name, const std::string &value);
		void setConnectionAlive(bool keepAlive = false);
		void setCacheDisabled();
		void addHeader();
		void addContent(const std::string &text, bool addLen = true);
		void addText(const std::string &text);
		void addTextLine(const std::string &text);
		static const char *getHttpStatusDesc(int statusCode);
	protected:
		ResponseValueList *prepareHeaderValues();
		void addHeaderValueToText(const std::string &name, const std::string &value);
		void buildResponseText();
	protected:
		struct mg_connection *m_conn;
		std::string m_text;
		std::string m_content;
		bool m_addContentLen;
		ResponseValueList m_headerValues;
		ResponseValueIndex m_headerValuesIndex;
		std::string m_statusText;
	};

	class WebServer {
	public:
		// construct
		WebServer();
		virtual ~WebServer();
		// attributes
		void setOptions(const ServerOptionSet &options);
		void setOption(const std::string &name, const std::string &value);
		void getOptions(ServerOptionSet &options) const;
		bool getOptionValue(const std::string &name, std::string &value) const;
		void getOptionValue(const std::string &name, std::string &value, const std::string &defValue) const;
		static void getValidOptions(ServerOptionList &output);
		static std::string getVersion();
		static void calcMD5(const std::string &text, std::string &output);
		static MongooseRequestMethodCode methodTextToCode(const std::string &text);
		// run
		virtual void init();
		void start();
		void stop();
		bool isRunning();
		virtual void *handleEvent(ServerHandlingEvent eventCode,
		struct mg_connection *conn,
			const struct mg_request_info *request_info);
	protected:
		virtual bool handleEvent(ServerHandlingEvent eventCode, MongooseConnection &connection, const MongooseRequest &request, MongooseResponse &response);
		virtual MongooseConnection *newConnection(struct mg_connection *conn);
		virtual MongooseRequest *newRequest(struct mg_connection *conn, const struct mg_request_info *request);
		virtual MongooseResponse *newResponse(struct mg_connection *conn);
		void checkStopped();
		const char **prepareOptions();
		void unprepareOptions();
		void checkMethodMap();
	protected:
		ServerOptionSet m_options;
		ServerOptionStorage m_optionStorage;
		bool m_statusRunning;
		bool m_prepared;
		struct mg_context *m_ctx;
		static MethodMap m_methodMap;
	};

}


#endif // _MONGCPP_H__